#include "MQTTClient.h"
#include "MQTTPacket/src/MQTTConnect.h"
#include "cJSON.h"
#include "delay.h"
#include "do_co2.h"
#include "do_dns.h"
#include "do_mqtt.h"
#include "do_pm25.h"
#include "mqtt_interface.h"
#include "wizchip_conf.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define MQTT_ETHERNET_MAX_SIZE (1024 * 2)

MQTTClient g_c = {0};
Network g_n = {0};
int g_conn_ok;
static uint8_t g_run_status = CONN;

uint8_t publish_flag = 0;   // 发布标志
uint32_t publish_count = 0; // 5秒定时计数器
#define PAYLOAD_BUFFER_SIZE 128
static char g_payload_buffer[PAYLOAD_BUFFER_SIZE]; // 用于构建JSON的缓冲区

mqttconn g_mqtt_params = {
    .mqttHostUrl = "a1QsjDLF7Rq.iot-as-mqtt.cn-shanghai.aliyuncs.com",
    .server_ip =
        {
            0,
        },        /*Define the Connection Server IP*/
    .port = 1883, /*Define the connection service port number*/
    .clientid = "a1QsjDLF7Rq.W55MH32|securemode=2,signmethod=hmacsha256,"
                "timestamp=1752545118110|", /*Define the client ID*/
    .username = "W55MH32&a1QsjDLF7Rq",      /*Define the user name*/
    .passwd = "f0dcd6ce4df2493438e42dbd9dd789d348309201ac18f18dd158ddceea45fc5"
              "d", /*Define user passwords*/
    .pubtopic =
        "/sys/a1QsjDLF7Rq/W55MH32/thing/event/property/post", /*Define the
                                                                 publication
                                                                 message*/
    .subtopic =
        "/sys/a1QsjDLF7Rq/W55MH32/thing/service/property/set", /*Define
                                                                  subscription
                                                                  messages*/
    .pubQoS = QOS0, /*Defines the class of service for publishing messages*/
};

static char g_mqtt_recv_msg[513] = {0};
static uint8_t g_mqtt_recv_flag = 0;

MQTTMessage g_pubmessage = {
    .qos = QOS0,
    .retained = 0,
    .dup = 0,
    .id = 0,
};
MQTTPacket_willOptions g_willdata =
    MQTTPacket_willOptions_initializer; /* Will subject struct initialization */
MQTTPacket_connectData g_data =
    MQTTPacket_connectData_initializer; /*Define the parameters of the MQTT
                                           connection*/

/**
 * @brief Initializing the MQTT client side
 *
 * Initialize the MQTT client side with the given parameters, including network
 * configuration and MQTT connection parameters.
 *
 * @param sn socket number
 * @param send_buf send buffer pointer
 * @param recv_buf recv buffer pointer
 */
void mqtt_init(uint8_t sn, uint8_t *send_buf, uint8_t *recv_buf) {
  wiz_NetInfo get_info = {0};
  wizchip_getnetinfo(&get_info);
  /* DNS parsing */
  if (do_dns(send_buf, (uint8_t *)g_mqtt_params.mqttHostUrl,
             g_mqtt_params.server_ip)) {
    while (1) {
    }
  }
  NewNetwork(&g_n, sn); /*Obtain network configuration information*/
  ConnectNetwork(&g_n, g_mqtt_params.server_ip,
                 g_mqtt_params.port); /*Connect to the MQTT server*/
  MQTTClientInit(&g_c, &g_n, 1000, send_buf, MQTT_ETHERNET_MAX_SIZE, recv_buf,
                 MQTT_ETHERNET_MAX_SIZE);
  g_data.will = g_willdata;
  g_data.willFlag = 0; /* will flag: If the will annotation bit is 0, the
                        following will-related settings are invalid*/
  g_willdata.qos = g_mqtt_params.willQoS; /* will QoS */
  g_willdata.topicName.lenstring.data =
      g_mqtt_params.willtopic; /* will topic */
  g_willdata.topicName.lenstring.len =
      strlen(g_willdata.topicName.lenstring.data); /* will topic len */
  g_willdata.message.lenstring.data = g_mqtt_params.willmsg; /* will message */
  g_willdata.message.lenstring.len =
      strlen(g_willdata.message.lenstring.data); /* will message len */
  g_willdata.retained = 0;
  g_willdata.struct_version = 3;
  g_data.MQTTVersion = 4;
  g_data.clientID.cstring = g_mqtt_params.clientid;
  g_data.username.cstring = g_mqtt_params.username;
  g_data.password.cstring = g_mqtt_params.passwd;
  g_data.keepAliveInterval = 30;
  g_data.cleansession = 1;
}

/**
 * @brief Cloud JSON message parsing
 *
 * Parses the given JSON message and executes the corresponding operation based
 * on the parsed result.
 *
 * @param msg ：JSON message pointer
 */
void json_decode(char *msg) {
  cJSON *jsondata = NULL;
  cJSON *params = NULL;
  cJSON *led = NULL;
  jsondata = cJSON_Parse(msg);
  if (jsondata == NULL) {
    printf("json parse fail.\r\n");
    return;
  }
  params = cJSON_GetObjectItem(jsondata, "params");
  led = cJSON_GetObjectItem(params, "LEDSwitch");
  if (led->valueint == 1) {
    printf("LED ON\r\n");
  } else {
    printf("LED OFF\r\n");
  }
  cJSON_Delete(jsondata);
}

/**
 * @brief mqtt Receive message callback function
 *
 * This function is called when a message is received. The function will parse
 * the message content and process it accordingly.
 *
 * @param md :message data pointer
 */
void message_arrived(MessageData *md) {
  char topicname[64] = {0};
  char msg[512] = {0};
  sprintf(topicname, "%.*s", md->topicName->lenstring.len,
          md->topicName->lenstring.data);
  sprintf(msg, "%.*s", (int)md->message->payloadlen,
          (char *)md->message->payload);
  printf("recv:%s,%s\r\n\r\n", topicname, msg);

  g_mqtt_recv_flag = 1;
  memset(g_mqtt_recv_msg, 0, sizeof(g_mqtt_recv_msg));
  strcpy(g_mqtt_recv_msg, msg);
}

/**
 * @brief Perform MQTT operations
 *
 * Perform the corresponding operations of MQTT based on the current operating
 * state, including connecting, subscribing, publishing messages, and
 * maintaining connections.
 */

void do_mqtt(void) {
  uint8_t ret = 0;
  switch (g_run_status) {
  case CONN: {
    ret = MQTTConnect(&g_c, &g_data); /* Connect to the MQTT server */
    printf("Connect to the MQTT server: %d.%d.%d.%d:%d\r\n",
           g_mqtt_params.server_ip[0], g_mqtt_params.server_ip[1],
           g_mqtt_params.server_ip[2], g_mqtt_params.server_ip[3],
           g_mqtt_params.port);
    printf("Connected:%s\r\n\r\n", ret == SUCCESSS ? "success" : "failed");
    if (ret != SUCCESSS) {
      g_run_status = ERR;
    } else {
      g_run_status = SUB;
    }
    break;
  }
  case SUB: {
    ret = MQTTSubscribe(&g_c, g_mqtt_params.subtopic, g_mqtt_params.subQoS,
                        message_arrived); /* Subscribe to Topics */
    printf("Subscribing to %s\r\n", g_mqtt_params.subtopic);
    printf("Subscribed:%s\r\n\r\n", ret == SUCCESSS ? "success" : "failed");
    if (ret != SUCCESSS) {
      g_run_status = ERR;
    } else {
      g_run_status = PUB_MESSAGE;
    }
    break;
  }
  case PUB_MESSAGE: {
    // 动态构建JSON负载
    snprintf(g_payload_buffer, PAYLOAD_BUFFER_SIZE,
             "{\"id\":\"123\",\"version\":\"1.0\","
             "\"params\":{\"co2\":%d,\"PM2_5\":%d},"
             "\"method\":\"thing.event.property.post\"}",
             g_co2_concentration, g_pm25_concentration);

    g_pubmessage.qos = QOS0;
    g_pubmessage.payload = g_payload_buffer;
    g_pubmessage.payloadlen = strlen(g_payload_buffer);
    ret = MQTTPublish(&g_c, (char *)&(g_mqtt_params.pubtopic),
                      &g_pubmessage); /* Publish message */
    if (ret != SUCCESSS) {
      g_run_status = ERR;
    } else {
      printf("publish:%s,%s\r\n\r\n", g_mqtt_params.pubtopic, g_payload_buffer);
      g_run_status = KEEPALIVE;
    }
    break;
  }
  case KEEPALIVE: {
    if (MQTTYield(&g_c, 30) != SUCCESSS) /* keepalive MQTT */
    {
      g_run_status = ERR;
    } else {
      g_run_status = RECV; // 成功则返回接收状态
    }
    break; // 添加break防止进入RECV状态两次
  }
  case RECV: {
    if (g_mqtt_recv_flag) {
      g_mqtt_recv_flag = 0;
      json_decode(g_mqtt_recv_msg);
    }

    // 添加5秒定时触发
    if (publish_flag) {
      publish_flag = 0;           // 清除标志
      g_run_status = PUB_MESSAGE; // 触发发布状态
    }
    break;
  }
  case ERR: /* Running error */
    printf("system ERROR!");
    delay_ms(1000);
    g_run_status = CONN;
    break;

  default:
    break;
  }
}
